package utility

import (
	"context"
	"fmt"
	"os"
	"sync"

	"github.com/gogf/gf/v2/container/gmap"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/util/gconv"
)

// ConstantContext 系统参数配置上下文
type ConstantContext struct {
	// 使用并发安全的map存储配置
	constants *gmap.StrAnyMap
	// 初始化锁
	initOnce sync.Once
}

var (
	// 单例实例
	constantContext *ConstantContext
	// 单例初始化锁
	instanceOnce sync.Once
)

// NewConstantContext 创建新的上下文实例
func NewConstantContext() *ConstantContext {
	return &ConstantContext{
		constants: gmap.NewStrAnyMap(true), // true表示并发安全
	}
}

// Instance 获取单例实例
func InstanceConstantContext() *ConstantContext {
	instanceOnce.Do(func() {
		constantContext = NewConstantContext()
	})
	return constantContext
}

// Init 初始化加载配置
func (c *ConstantContext) InitConstantContext(ctx context.Context) error {
	var initErr error
	c.initOnce.Do(func() {
		// 从数据库加载所有配置
		configs, err := g.Model("sys_config").Where("enabled=?", 1).All()
		if err != nil {
			initErr = err
			return
		}

		for _, config := range configs {
			code := config["code"].String()
			content := config["content"].String()
			c.constants.Set(code, content)
		}
	})
	return initErr
}

// PutConstant 添加/更新系统常量
func (c *ConstantContext) PutConstant(code string, value interface{}) {
	if code == "" || value == nil {
		return
	}
	c.constants.Set(code, value)
}

// DeleteConstant 删除常量
func (c *ConstantContext) DeleteConstant(code string) {
	if code == "" {
		return
	}
	c.constants.Remove(code)
}

// Get 获取配置值
func (c *ConstantContext) Get(code string) interface{} {
	return c.constants.Get(code)
}

// GetStr 获取字符串配置
func (c *ConstantContext) GetStr(code string) string {
	return c.constants.GetVar(code).String()
}

// GetConfig 获取系统配置（环境变量优先，其次内存缓存）
func GetSysConfig(code string, resultPtr interface{}, nullThrowExp bool) error {
	// 1. 优先从环境变量获取
	content := os.Getenv(code)
	if content == "" {
		// 2. 从内存缓存获取
		content = InstanceConstantContext().GetStr(code)
	}

	// 处理空值情况
	if content == "" {
		if nullThrowExp {
			return fmt.Errorf("系统配置不存在，code为：%s", code)
		}
		return nil
	}

	// 类型转换
	err := gconv.Scan(content, resultPtr)
	if err != nil {
		if nullThrowExp {
			return fmt.Errorf("系统配置格式错误，code=%s，content=%s", code, content)
		}
		return nil
	}

	return nil
}
